
#include "gpio.h"
#include "tim.h"
#include "drv_pwm.h"

#ifdef GPIO_PWM

#define MAX_PWM_CHANNELS 2

typedef struct {
    GPIO_TypeDef *port;  // GPIO 端口
    uint16_t pin;        // GPIO 引脚
    uint16_t period;     // PWM 周期
    uint16_t duty_cycle; // PWM 占空比
    uint16_t counter;    // 当前计数
    uint32_t duration;   // 持续时间，单位为ms（0表示无限持续）
    uint32_t elapsed;    // 已持续时间，单位为ms
    uint8_t enabled;     // 状态：1=启用，0=停用
} PWM_Channel;

static PWM_Channel pwm_channels[MAX_PWM_CHANNELS] = 
{
    {GPIOB, GPIO_PIN_12, 100, 50, 0, 0, 0, 0}, // 通道 1，默认停用
    {GPIOB, GPIO_PIN_14, 100, 60, 0, 0, 0, 0}, // 通道 2，默认停用
};

#include "app_midi.h"
void drv_pwm_tim_handle(void)
{
    for (int i = 0; i < MAX_PWM_CHANNELS; i++)
    {
        PWM_Channel *channel = &pwm_channels[i];

        // 检查是否启用当前通道
        if (channel->enabled)
        {
            channel->counter++;
            channel->elapsed++; // 累计持续时间

            // 输出高低电平逻辑
            if (channel->counter < channel->duty_cycle)
            {
                HAL_GPIO_WritePin(channel->port, channel->pin, GPIO_PIN_SET); // 输出高电平
            }
            else
            {
                HAL_GPIO_WritePin(channel->port, channel->pin, GPIO_PIN_RESET); // 输出低电平
            }

            // 周期结束，重置计数器
            if (channel->counter >= channel->period)
            {
                channel->counter = 0;
            }

            // 检查持续时间是否达到限制
            if (channel->duration > 0 && channel->elapsed >= channel->duration)
            {
                channel->enabled = 0;  // 停止当前通道
                // HAL_GPIO_WritePin(channel->port, channel->pin, GPIO_PIN_RESET); // 确保引脚低电平
                app_taban_switch_state(i);  //切换状态，确保只有打击、回机给duration值
            }
        }
        else
        {
            // 如果通道被禁用，确保引脚始终为低电平
            HAL_GPIO_WritePin(channel->port, channel->pin, GPIO_PIN_RESET);
        }
    }
}



void drv_g_pwm_start(uint8_t pwm_channel, uint16_t duration, uint16_t period, uint8_t duty_cycle)
{
    // 检查通道号是否合法
    if (pwm_channel >= MAX_PWM_CHANNELS)
    {
        return; // 通道号超出范围，直接返回
    }

    // 校验占空比范围（0% - 100%）
    if (duty_cycle > 100)
    {
        duty_cycle = 100;
    }

    // 获取指定通道
    PWM_Channel *channel = &pwm_channels[pwm_channel];

    // 配置 PWM 通道参数
    channel->period = period;                      // 设置周期
    channel->duty_cycle = (period * duty_cycle) / 100; // 计算占空比对应的计数值
    channel->duration = duration;
    channel->elapsed = 0;
    channel->counter = 0;                          // 重置计数器
    channel->enabled = 1;                          // 启用当前通道
}

void drv_g_pwm_stop(uint8_t pwm_channel)
{
    // 检查通道号是否合法
    if (pwm_channel >= MAX_PWM_CHANNELS)
    {
        return; // 通道号超出范围，直接返回
    }

    // 获取指定通道
    PWM_Channel *channel = &pwm_channels[pwm_channel];

    // 禁用通道
    channel->enabled = 0; // 将通道的启用状态设为禁用

    // 确保引脚输出低电平
    HAL_GPIO_WritePin(channel->port, channel->pin, GPIO_PIN_RESET);

    // 重置通道相关参数（可选）
    channel->counter = 0;
    channel->duty_cycle = 0;
    channel->duration = 0;
    channel->elapsed = 0;
    channel->period = 0;
}


#endif


#ifdef TIM_PWM
TIM_HandleTypeDef pwm_tim;                // 定义全局定时器句柄
uint8_t pwm_status[2] = {0, 0};           // 记录两个通道的状态
uint32_t pwm_duration_ticks[2] = {0, 0};  // 记录两个通道的持续时间（以中断次数为单位）
uint32_t pwm_elapsed_ticks[2] = {0, 0};   // 记录两个通道的累计中断次数
uint32_t pwm_interrupt_period_us = 0;      // 记录定时器中断周期时间（单位：us）

/**
 * @brief 启动 PWM 输出
 * @param channel PWM 通道，例如 `TIM_CHANNEL_1` 或 `TIM_CHANNEL_2`
 * @param duty_cycle 占空比 (0-100)，单位为百分比
 * @param duration 持续时间，单位为 ms
 */
void drv_pwm_start(uint32_t channel, uint8_t duty_cycle, uint32_t duration)
{
    uint32_t ccr;
    uint8_t channel_idx = (channel == TIM_CHANNEL_1) ? 0 : 1;

    // 参数合法性检查
    if (duty_cycle > 100)
    {
        return; // 无效参数直接退出
    }

    // 根据占空比计算比较值
    uint32_t arr = __HAL_TIM_GET_AUTORELOAD(&pwm_tim) + 1;
    ccr = (arr * duty_cycle) / 100;
    if (ccr == 0)
    {
        ccr = 1; // 确保 CCR 不为 0
    }

    // 修改 CCR
    __HAL_TIM_SET_COMPARE(&pwm_tim, channel, ccr);

    // 如果持续时间不为 0，则转换为中断次数并记录
    if (duration > 0)
    {
        pwm_duration_ticks[channel_idx] = duration*1000 / pwm_interrupt_period_us;
        pwm_elapsed_ticks[channel_idx] = 0;
    }
    else
    {
        pwm_duration_ticks[channel_idx] = 0;  // 永久运行，无需停止
    }


    // 启动 PWM 输出
    if (pwm_status[channel_idx] == 0)
    {
        HAL_TIM_PWM_Start(&pwm_tim, channel);
        pwm_status[channel_idx] = 1;
    }

    // 启动更新中断，用于停止 PWM
    __HAL_TIM_ENABLE_IT(&pwm_tim, TIM_IT_UPDATE);
}

/**
 * @brief 停止 PWM 输出
 * @param channel PWM 通道，例如 `TIM_CHANNEL_1` 或 `TIM_CHANNEL_2`
 */
void drv_pwm_stop(uint32_t channel)
{
    uint8_t channel_idx = (channel == TIM_CHANNEL_1) ? 0 : 1;

    // 停止 PWM 输出
    HAL_TIM_PWM_Stop(&pwm_tim, channel);
    pwm_status[channel_idx] = 0;

    // 检查是否需要关闭更新中断
    if (pwm_status[0] == 0 && pwm_status[1] == 0)
    {
        __HAL_TIM_DISABLE_IT(&pwm_tim, TIM_IT_UPDATE);
    }
}

/**
 * @brief 初始化 PWM 模块
 * @param frequency PWM 频率，单位为 Hz
 */
void drv_pwm_init(uint32_t frequency)
{
    pwm_tim = PWM_TIMER;
    uint32_t arr;

    // 计算 ARR 值
    arr = 72000000 / (frequency * (pwm_tim.Init.Prescaler + 1)) - 1;
    if (arr > 65535)
    {
        // ARR 超出范围，打印错误日志或返回错误码
        return;
    }

    __HAL_TIM_SET_AUTORELOAD(&pwm_tim, arr); // 更新 ARR

    // 计算中断周期时间（单位：us）
    uint32_t timer_tick_frequency = HAL_RCC_GetPCLK1Freq() / (pwm_tim.Init.Prescaler + 1); // 定时器计数频率
    pwm_interrupt_period_us = (arr * 1000000) / timer_tick_frequency;

    pwm_status[0] = pwm_status[1] = 0;
}


#include "app_midi.h"
/**
 * @brief 处理中断并更新 PWM 通道的状态，检查是否需要停止 PWM 输出
 * @param None
 * @retval None
 */
void drv_pwm_interrupt_handle(void)
{
    uint8_t channel_idx;

    // 遍历两个 PWM 通道，检查是否需要停止
    for (channel_idx = 0; channel_idx < 2; channel_idx++)
    {
        if (pwm_status[channel_idx] == 1)  // 如果当前通道的 PWM 正在运行
        {
            if(pwm_duration_ticks[channel_idx] > 0)
            {
                pwm_elapsed_ticks[channel_idx]++;  // 累计中断次数

                // 如果已经达到设定的持续时间，停止 PWM 输出
                if (pwm_elapsed_ticks[channel_idx] >= pwm_duration_ticks[channel_idx])
                {
                    uint32_t channel = (channel_idx == 0) ? TIM_CHANNEL_1 : TIM_CHANNEL_2;  // 确定通道
                    drv_pwm_stop(channel);  // 停止 PWM 输出
                    app_taban_switch_state(channel_idx);
                }
            }
            
        }
    }
}


#endif

